{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 演示0203：矩阵性质"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 案例1：矩阵的逆"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">**逆矩阵与求解**  \n",
    "* 维度为*(M,M)*的矩阵*A*(方阵)的逆矩阵表示为：$A^{-1}$\n",
    "* 逆矩阵的性质：\n",
    " * $AA^{-1}=I$，其中$I$是*(M,M)*的单位方阵\n",
    " * $(A^{-1})^{-1}=A$，也就是说，方阵的逆矩阵的逆矩阵就是本身\n",
    " * $(AB)^{-1}=B^{-1}A^{-1}$\n",
    " * $(A^{k})^{-1}=(A^{-1})^{k}$\n",
    "* 矩阵求逆：*np.linalg.inv(A)*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1.00000000e+00  1.77635684e-15  0.00000000e+00]\n",
      " [ 0.00000000e+00  1.00000000e+00  0.00000000e+00]\n",
      " [-2.22044605e-16 -8.88178420e-16  1.00000000e+00]]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "A = np.array([[2, 2, 3],[1, -1, 0],[-1, 2, 1]])\n",
    "invA = np.linalg.inv(A)\n",
    "I = A.dot(invA) # 矩阵与其逆矩阵相乘，结果非常接近单位阵\n",
    "print(I)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">**奇异矩阵**  \n",
    "* 并非所有的方阵都有逆。没有逆矩阵的方阵称为奇异矩阵\n",
    "* 奇异矩阵的某种判断方法是：矩阵中的某行或列，通过线性变换后，与另外任意一行或列的数完全相同\n",
    " * 线性变换(或初等变换)：对某个数组，选择一批标量，仅对其执行加、减、乘、除四则运算操作。可以进行多次操作\n",
    " * 例如：矩阵$ \\left[\\begin{matrix}1 & 2 & 3 \\\\5 & 3 & 7 \\\\2 & 4 &6\\\\ \\end{matrix}\\right] $，其第一行[1,2,3]与2相乘后与第三行数据完全相同。因此该矩阵是奇异矩阵，没有逆"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = np.array([[1, 2, 3],[5, 3, 7], [2, 4, 6]])\n",
    "#invA = np.linalg.inv(A)    # 错误，奇异矩阵求逆报错"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 案例2：矩阵转置"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">**转置操作** \n",
    "* 转置矩阵相对原矩阵，是将元素的行列号互换：$ \\left(\n",
    "  \\begin{matrix}\n",
    "    1 & 2 & 3 & 4 \\\\\n",
    "    5 & 6 & 7 & 8 \\\\\n",
    "    9 & 10 & 11 & 12\n",
    "  \\end{matrix}\n",
    "  \\right)\n",
    "  =>\n",
    "  \\left(\n",
    "  \\begin{matrix}\n",
    "    1 & 5 & 9 \\\\\n",
    "    2 & 6 & 10 \\\\\n",
    "    3 & 7 & 11 \\\\\n",
    "    4 & 8 & 12\n",
    "  \\end{matrix}\n",
    "  \\right) $\n",
    "* 转置矩阵的性质\n",
    " * $(A^{T})^{T}=A$\n",
    " * $(AB)^{T}=B^{T}A^{T}$\n",
    " * $(A^{-1})^{T}=(A^{T})^{-1}$\n",
    "* 使用*A.T*或*np.tranpose(A)*计算转置矩阵\n",
    "* *(M,1)*列向量转置后变成*(1,M)*二维矩阵\n",
    "* *(M,)*一维数组无法通过*.T*或*transpose*函数转置成(M,1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 4.44089210e-16  4.44089210e-16 -6.66133815e-16]\n",
      " [ 0.00000000e+00 -1.77635684e-15  1.77635684e-15]\n",
      " [-8.88178420e-16 -8.88178420e-16  1.77635684e-15]]\n"
     ]
    }
   ],
   "source": [
    "A = np.array([[2, 2, 3],[1, -1, 0],[-1, 2, 1]])\n",
    "invA = np.linalg.inv(A)\n",
    "invAT = np.linalg.inv(A.T)\n",
    "print(invA.T - invAT)    # A的逆矩阵转置，相当于A转置再求逆。因此该结果接近0矩阵"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 案例3：矩阵的秩"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">**矩阵的秩**  \n",
    "* 将矩阵进行充分的(多次)初等变换/线性变换后，叠加到另一个行/列上，不全为0的行(或列)的数目，就是该矩阵的秩\n",
    "* 对于*(M,M)*可逆矩阵，其秩就是*M；对于不可逆矩阵，秩小于*M*；对于零方针，秩为零\n",
    "* 对于*(M,N)*矩阵，秩最大为*M*和*N*中的较小者，表示为*min(M,N)*\n",
    "* 秩为*M*或*N*的矩阵，称为满秩矩阵\n",
    "* 使用*np.linalg.matrix_rank(A)*计算矩阵的秩"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n",
      "2\n",
      "3\n"
     ]
    }
   ],
   "source": [
    "A1 = np.array([[2, 1, 3],[6, 6, 10],[2, 7, 6]])\n",
    "A2 = np.array([[2, 1, 3],[4, 2, 6],[2, 7, 6]])\n",
    "A3 = np.array([[2, 1, 3],[6, 6, 10],[2, 7, 6],[1,3,5]])\n",
    "print(np.linalg.matrix_rank(A1)) # 非奇异矩阵，满秩矩阵\n",
    "print(np.linalg.matrix_rank(A2)) # 奇异矩阵，无法达到满秩\n",
    "print(np.linalg.matrix_rank(A3)) # 4x3非奇异矩阵，秩为3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 案例4：矩阵的特征分解"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">**特征分解**  \n",
    "* 方阵的特征值与特征向量：如果存在非零向量$\\nu$和常数$\\lambda$，使得方阵$A$实现：$A\\nu=\\lambda \\nu$\n",
    " * 称$\\nu$为特征向量，$\\lambda$为这个特征向量对应的特征值\n",
    " * 这就是说，原矩阵与特征向量的乘积，相当于将特征向量放大特征值倍数\n",
    " * 对于*(M,M)*可逆矩阵(满秩矩阵)，存在*M*个非零的特征值，每个特征值对应1个特征向量\n",
    " * 对于不可逆矩阵，必定存在一个特征值为零\n",
    "* 特征分解：$A=Vdiag(\\Lambda) V^{-1}$\n",
    " * $V$为所有特征向量按列组合而成。即：$V$中的每一列是一个特征向量\n",
    " * $\\Lambda$是所有特征值构成的一维数组。特征值在数组中的顺序与其对应的特征向量在$V$中的顺序一致\n",
    " * $diag(\\Lambda)$是由特征值数组作为主对角线元素的对角矩阵\n",
    "* 特征值和特征向量的意义：\n",
    " * 特征向量代表了该矩阵的某个特性，或者说空间方向；一个矩阵有多个特性，或者说在空间上向多个方向延申\n",
    " * 特征值衡量了该特性的强弱。特征值越大，表明该特性(空间方向)越强劲\n",
    " * 在机器学习的数据预处理中，有一种称为主成分分析(PCA)的方法，可以从大量的特性中筛选出最重要的若干个特性，就是借助了特征值和特征向量计算\n",
    "* 使用*np.linalg.eig(A)*来求特征值和特征向量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[-5.55111512e-16 -3.33066907e-16  2.22044605e-16]\n",
      "[[-4.44089210e-16 -5.77315973e-15 -3.99680289e-15]\n",
      " [ 6.66133815e-16 -1.11022302e-15 -6.64118072e-16]\n",
      " [-1.11022302e-16  6.66133815e-16  7.77156117e-16]]\n",
      "[-6.05551275e-01 -1.77635684e-15  6.60555128e+00]\n"
     ]
    }
   ],
   "source": [
    "A= np.array([[2, 2, 3],[1, -1, 0],[-1, 2, 1]])\n",
    "lambdas,V = np.linalg.eig(A) # lambdas为特征值构成的数组；V为所有特征向量按列构成的矩阵\n",
    "r1 = A.dot(V[:,0]) # 原矩阵与第一个特征向量(特征矩阵中的第一列)相乘\n",
    "r2 = lambdas[0]*V[:,0] # 第一个特征值与第一个特征向量(特征矩阵中的第一列)相乘\n",
    "print(r1 - r2)    # 接近0\n",
    "\n",
    "r3 = A - V.dot(np.diag(lambdas)).dot(np.linalg.inv(V)) # A减去其特征分解矩阵，其结果应接近0\n",
    "print(r3)\n",
    "\n",
    "A2 = np.array([[1,2,3],[2,4,6],[-1, 2, 1]]) # 奇异矩阵，第2个特征值接近0\n",
    "lambdas, V = np.linalg.eig(A2)\n",
    "print(lambdas)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 案例5：范数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">** $p$范数被定义为： $\\|x\\|_p=(\\sum_i|x_i|^{p})^{\\frac{1}{p}}$**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">**向量或一维数组的范数**  \n",
    "* 1范数：向量各元素绝对值之和 $\\|x\\|=\\sum_i|x_i|$ \n",
    "* 2范数：向量各元素平方和再开方  $\\|x\\|_2=\\sqrt{\\sum_i x_i^2} $\n",
    "* 正无穷范数：向量各元素绝对值最大值\n",
    "* 负无穷范数：向量各元素绝对值最小值"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">** (M,N)矩阵的范数**  \n",
    "* 1范数：列和范数，即对每列向量求和(元素绝对值求和)，返回和的最大值$\\|A\\|_1=max_j \\sum_{i=1}^{m}|a_{i,j}|$  \n",
    "* 正无穷范数：行和范数，即对每行求和(元素绝对值求和)，返回和的最大值$\\|A\\|_\\infty=max_i \\sum_{j=1}^{n}|a_{i,j} |$\n",
    "* 2范数：谱范数，即$A^{T}A$矩阵的最大特征值的开平方 $\\|A\\|_2= \\sqrt{\\lambda_1}$\n",
    " * $\\lambda_{1}$是$A^{T}A$的最大特征值\n",
    "* $F$范数：矩阵元素值的平方和再开方 $\\|A\\|_F= \\sqrt{(\\sum_{i=1}^{m}\\sum_{j=1}^{n}a_{i,j}^2)}$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">** 使用*np.linalg.norm*求向量或矩阵的范数**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "19.0\n",
      "16.25817258701917\n",
      "22.0\n",
      "16.583123951777\n"
     ]
    }
   ],
   "source": [
    "A1 = np.array([[2, 1, 3],[6, 6, 10],[2, 7, 6]])\n",
    "print(np.linalg.norm(A1, ord=1)) # 1范数\n",
    "print(np.linalg.norm(A1, ord=2)) # 2范数\n",
    "print(np.linalg.norm(A1, ord=np.inf)) # 正无穷范数\n",
    "print(np.linalg.norm(A1, ord='fro')) # F范数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 案例6：正交向量与对称矩阵"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">**正交向量**  \n",
    "* 两个同维度的数组或向量，如果它们的内积和为零，那么这它们就是正交的\n",
    "* 在空间中，可以想象成这两个向量互相垂直"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">**对称矩阵**  \n",
    "* 对称矩阵(方阵)是指，以主对角线为中心，左下方和右上方对应位置的元素值相等。即：$A[i,j]=A[j,i]$\n",
    "* 如果*A*是对称矩阵，则*A*的各个特征向量都是正交的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-2.7755575615628914e-16 2.498001805406602e-16 3.885780586188048e-16\n"
     ]
    }
   ],
   "source": [
    "A = np.array([[0,1,2,3,4],[1,0,1,2,3],[2,1,0,1,2],[3,2,1,0,1],[4,3,2,1,0]])\n",
    "lambdas, V = np.linalg.eig(A)\n",
    "print(V[:,0].dot(V[:,1]), V[:,0].dot(V[:,2]), V[:,0].dot(V[:,3]))    # 各特征向量两两内积和接近0"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
